package leetcode.editor.cn;

import org.junit.Assert;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class P391PerfectRectangle {
    public static void main(String[] args) {
        Solution solution = new P391PerfectRectangle().new Solution();
        int[][] rectangles = {{0, 0, 1, 1}, {0, 1, 3, 2}, {1, 0, 2, 2}};
        Assert.assertEquals(solution.isRectangleCover(rectangles), true);
    }

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        class Point {
            int x;
            int y;

            public Point(int x, int y) {
                this.x = x;
                this.y = y;
            }

            public int getX() {
                return x;
            }

            public void setX(int x) {
                this.x = x;
            }

            public int getY() {
                return y;
            }

            public void setY(int y) {
                this.y = y;
            }

            @Override
            public boolean equals(Object o) {
                if (this == o) return true;
                if (o == null || getClass() != o.getClass()) return false;
                Point point = (Point) o;
                return x == point.x && y == point.y;
            }

            @Override
            public int hashCode() {
                return Objects.hash(x, y);
            }
        }

        public boolean isRectangleCover(int[][] rectangles) {
            int left = Integer.MAX_VALUE, right = Integer.MIN_VALUE,
                    low = Integer.MAX_VALUE, high = Integer.MIN_VALUE;
            int virtual = 0;
            Map<Point, Integer> pointMap = new HashMap<>();
            for (int[] rectangle : rectangles) {

                left = Math.min(left, rectangle[0]);

                right = Math.max(right, rectangle[2]);

                low = Math.min(low, rectangle[1]);

                high = Math.max(high, rectangle[3]);

                virtual += (rectangle[2] - rectangle[0]) * (rectangle[3] - rectangle[1]);
                Point point1 = new Point(rectangle[0], rectangle[1]);
                Point point4 = new Point(rectangle[2], rectangle[1]);
                Point point2 = new Point(rectangle[0], rectangle[3]);
                Point point3 = new Point(rectangle[2], rectangle[3]);
                pointMap.compute(point1, (point, integer) -> integer == null ? 1 : integer + 1);
                pointMap.compute(point2, (point, integer) -> integer == null ? 1 : integer + 1);
                pointMap.compute(point3, (point, integer) -> integer == null ? 1 : integer + 1);
                pointMap.compute(point4, (point, integer) -> integer == null ? 1 : integer + 1);
            }
            int real = (right - left) * (high - low);
            Point pointMinMin = new Point(left, low);
            Point pointMinMax = new Point(left, high);
            Point pointMaxMin = new Point(right, low);
            Point pointMaxMax = new Point(right, high);
            if (virtual != real ||
                    pointMap.getOrDefault(pointMinMin, 0) != 1 ||
                    pointMap.getOrDefault(pointMinMax, 0) != 1 ||
                    pointMap.getOrDefault(pointMaxMin, 0) != 1 ||
                    pointMap.getOrDefault(pointMaxMax, 0) != 1) {
                return false;
            }
            pointMap.remove(pointMinMin);
            pointMap.remove(pointMinMax);
            pointMap.remove(pointMaxMin);
            pointMap.remove(pointMaxMax);
            for (Map.Entry<Point, Integer> entry : pointMap.entrySet()) {
                if (entry.getValue() != 2 && entry.getValue() != 4) {
                    return false;
                }
            }
            return true;
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}